package com.khoayang.littlefighterchaos.game;

import java.util.ArrayList;

import org.cocos2d.layers.CCLayer;
import org.cocos2d.nodes.CCDirector;
import org.cocos2d.nodes.CCSprite;
import org.cocos2d.sound.SoundEngine;
import org.cocos2d.transitions.CCFlipYTransition;
import org.cocos2d.types.CGPoint;
import org.cocos2d.types.CGRect;
import org.cocos2d.types.CGSize;

import com.khoayang.littlefighterchaos.menu.MainMenuScence;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class GamePad extends CCLayer {
	public enum KEY {
		UP, DOWN, LEFT, RIGHT, ATTACK, DEFEND, JUMP
	}

	private static ArrayList<GamePadListener> _observerGamePads = new ArrayList<GamePadListener>();

	// virtual pad
	private CCSprite _attackButton;
	private CCSprite _defendButton;
	private CCSprite _jumpButton;
	private CCSprite _refreshButton;
	private CCSprite _backButton;
	private CCSprite _pauseButton;
	private CCSprite _playButton;
	
	static float sensorX;
	static float sensorY;
	static float sensorZ;

	// keyboard
	private static ArrayList<KEY> _DownButtons = new ArrayList<KEY>();

	// sensor
	private static long lastUpdate;
	private static boolean _playWithSensor = false;
	private static float x0 = 100;
	
	private static float offSet;

	private Context _context;
	// init pad
	public GamePad(Context context) {
		this.setIsTouchEnabled(true);
		this.setIsKeyEnabled(true);

		_context = context;
		offSet = 1.0f;
		_attackButton = CCSprite.sprite("GamePad/AttackButton.png");
		_defendButton = CCSprite.sprite("GamePad/DefendButton.png");
		_jumpButton = CCSprite.sprite("GamePad/MyJumpButton.png");
		_refreshButton = CCSprite.sprite("GamePad/RefreshButton.png");
		_backButton = CCSprite.sprite("GamePad/BackButton.png");
		_pauseButton = CCSprite.sprite("GamePad/PauseButton.png");
		_playButton = CCSprite.sprite("GamePad/PlayButton.png");
		
		
		_jumpButton.setOpacity(100);
		_attackButton.setOpacity(100);
		_defendButton.setOpacity(100);
		_refreshButton.setOpacity(100);
		_backButton.setOpacity(100);
		_pauseButton.setOpacity(100);
		_playButton.setOpacity(100);
		
		CGSize winSize = CCDirector.sharedDirector().winSize();

		_refreshButton.setScale((winSize.height/12)/_refreshButton.getContentSize().height);
		_backButton.setScale((winSize.height/12)/_backButton.getContentSize().height);
		_pauseButton.setScale((winSize.height/12)/_pauseButton.getContentSize().height);
		_playButton.setScale((winSize.height/12)/_playButton.getContentSize().height);
		_attackButton.setScale((winSize.height/5.08f)/_attackButton.getContentSize().height);
		_defendButton.setScale((winSize.height/5.08f)/_defendButton.getContentSize().height);
		_jumpButton.setScale((winSize.height/5.08f)/_jumpButton.getContentSize().height);
		
		_attackButton.setPosition(winSize.width -  (winSize.height/10.16f)*3f, 
				(winSize.height/10.16f)*1);
		_defendButton.setPosition((winSize.height/10.16f)*2,
				(winSize.height/10.16f)*2);
		_jumpButton.setPosition(winSize.width - (winSize.height/10.16f)*1,
				(winSize.height/10.16f)*3);
		
		_refreshButton.setPosition(winSize.width - _refreshButton.getScale()*_refreshButton.getContentSize().width/2, 
				winSize.height- (winSize.height/24));
		_backButton.setPosition(_backButton.getScale()*_backButton.getContentSize().width/2, 
				winSize.height -(winSize.height/24));
		_pauseButton.setPosition(winSize.width/2-winSize.height/12,
				winSize.height - (winSize.height/24));
		_playButton.setPosition(winSize.width/2+winSize.height/12,
				winSize.height - (winSize.height/24));
		
		addChild(_attackButton);
		addChild(_defendButton);
		addChild(_jumpButton);
		addChild(_refreshButton);
		addChild(_backButton);
		addChild(_pauseButton);
		addChild(_playButton);
		
		lastUpdate = System.currentTimeMillis();
	}

	public void addObserver(GamePadListener o) {
		_observerGamePads.add(o);
	}

	public void removeObserver(GamePadListener o) {
		_observerGamePads.remove(o);
	}

	// /////////////BUTTON////////////////////////////////////////////////////
	private static void AddButtonJump(MotionEvent event) {
		if (!_DownButtons.contains(KEY.JUMP)) {
			_DownButtons.add(KEY.JUMP);
			
			for (GamePadListener element : _observerGamePads) {
				element.jumpButtonDown(event);
			}
		}
	}

	private static void AddButtonDefend(MotionEvent event) {
		if (!_DownButtons.contains(KEY.DEFEND)) {
			_DownButtons.add(KEY.DEFEND);
			for (GamePadListener element : _observerGamePads) {
				element.defendButtonDown(event);
			}
		}
	}

	private static void AddButtonAttack(MotionEvent event) {
		if (!_DownButtons.contains(KEY.ATTACK)) {
			_DownButtons.add(KEY.ATTACK);
			for (GamePadListener element : _observerGamePads) {
				element.attackButtonDown(event);
			}
		}
	}

	private static void AddButtonRight(MotionEvent event) {
		if (!_DownButtons.contains(KEY.RIGHT)) {
			_DownButtons.add(KEY.RIGHT);
			for (GamePadListener element : _observerGamePads) {
				element.rightButtonDown(event);
			}
		}
	}

	private static void AddButtonLeft(MotionEvent event) {
		if (!_DownButtons.contains(KEY.LEFT)) {
			_DownButtons.add(KEY.LEFT);
			for (GamePadListener element : _observerGamePads) {
				element.leftButtonDown(event);
			}
		}
	}

	private static void AddButtonDown(MotionEvent event) {
		if (!_DownButtons.contains(KEY.DOWN)) {
			_DownButtons.add(KEY.DOWN);
			for (GamePadListener element : _observerGamePads) {
				element.downButtonDown(event);
			}
		}
	}

	private static void AddButtonUp(MotionEvent event) {
		if (!_DownButtons.contains(KEY.UP)) {
			_DownButtons.add(KEY.UP);
			for (GamePadListener element : _observerGamePads) {
				element.upButtonDown(event);
			}
		}
	}

	private static void RemoveButtonJump(MotionEvent event) {
		if (_DownButtons.contains(KEY.JUMP)) {
			_DownButtons.remove(KEY.JUMP);
			for (GamePadListener element : _observerGamePads) {
				element.jumpButtonUp(event);
			}
		}
	}

	private static void RemoveButtonDefend(MotionEvent event) {
		if (_DownButtons.contains(KEY.DEFEND)) {
			_DownButtons.remove(KEY.DEFEND);
			for (GamePadListener element : _observerGamePads) {
				element.defendButtonUp(event);
			}
		}
	}

	private static void RemoveButtonAttack(MotionEvent event) {
		if (_DownButtons.contains(KEY.ATTACK)) {
			_DownButtons.remove(KEY.ATTACK);
			for (GamePadListener element : _observerGamePads) {
				element.attackButtonUp(event);
			}
		}
	}

	private static void RemoveButtonRight(MotionEvent event) {
		if (_DownButtons.contains(KEY.RIGHT)) {
			_DownButtons.remove(KEY.RIGHT);
			for (GamePadListener element : _observerGamePads) {
				element.rightButtonUp(event);
			}
		}
	}

	private static void RemoveButtonLeft(MotionEvent event) {
		if (_DownButtons.contains(KEY.LEFT)) {
			_DownButtons.remove(KEY.LEFT);
			for (GamePadListener element : _observerGamePads) {
				element.leftButtonUp(event);
			}
		}
	}

	private static void RemoveButtonDown(MotionEvent event) {
		if (_DownButtons.contains(KEY.DOWN)) {
			_DownButtons.remove(KEY.DOWN);
			for (GamePadListener element : _observerGamePads) {
				element.downButtonUp(event);
			}
		}
	}

	private static void RemoveButtonUp(MotionEvent event) {
		if (_DownButtons.contains(KEY.UP)) {
			_DownButtons.remove(KEY.UP);
			for (GamePadListener element : _observerGamePads) {
				element.upButtonUp(event);
			}
		}
	}

	// ////////////////////////////////////////////////////////////////////////

	// //////////MULTITOUCH////////////////////////////////////////////////////
	private static boolean checkIsTouch(CCSprite _sprite, float x, float y) {
		CGPoint convertedPoint = CCDirector.sharedDirector().convertToGL(
				CGPoint.ccp(x, y));

		CGPoint spriteTopLeftPos = CGPoint.ccp(_sprite.getPosition().x
				- _sprite.getContentSize().width / 2, _sprite.getPosition().y
				- _sprite.getContentSize().height / 2);
		CGRect spriteRect = new CGRect(spriteTopLeftPos,
				_sprite.getContentSize());
		if (spriteRect.contains(convertedPoint.x, convertedPoint.y))
			return true;
		return false;
	}

	public void buttonDown(MotionEvent event, float x, float y) {
		if(checkIsTouch(_refreshButton, x, y))
		{
			x0 = 100;
			_refreshButton.setOpacity(200);
		}
		
		if(checkIsTouch(_backButton, x, y))
		{
			SoundEngine.sharedEngine().pauseSound();
			CCDirector.sharedDirector().replaceScene(new CCFlipYTransition(1,new MainMenuScence(_context),1));
		}
		
		if(checkIsTouch(_pauseButton, x, y))
		{
			_pauseButton.setOpacity(200);
			SoundEngine.sharedEngine().pauseSound();
			CCDirector.sharedDirector().pause();
		}
		
		if(checkIsTouch(_playButton, x, y))
		{
			_playButton.setOpacity(200);
			SoundEngine.sharedEngine().resumeSound();
			CCDirector.sharedDirector().resume();
		}
		
		if (checkIsTouch(_attackButton, x, y)) {
			// notify to observers

			_attackButton.setOpacity(200);
			AddButtonAttack(event);
		}
		if (checkIsTouch(_defendButton, x, y)) {
			// notify to observers

			_defendButton.setOpacity(200);
			AddButtonDefend(event);
		}
		if (checkIsTouch(_jumpButton, x, y)) {
			// notify to observers
			
			_jumpButton.setOpacity(200);
			AddButtonJump(event);
		}
	}

	public void buttonUp(MotionEvent event, float x, float y) {
		if(checkIsTouch(_refreshButton, x, y))
		{
			_refreshButton.setOpacity(100);
		}
		
		if(checkIsTouch(_pauseButton, x, y))
		{
			_pauseButton.setOpacity(100);
		}
		
		if(checkIsTouch(_playButton, x, y))
		{
			_playButton.setOpacity(100);
		}
		
		if (checkIsTouch(_attackButton, x, y)) {
			Log.w("GamePad: attack button end", "null");
			// notify to observers

			_attackButton.setOpacity(100);
			RemoveButtonAttack(event);
		}
		
		
		if (checkIsTouch(_defendButton, x, y)) {
			Log.w("GamePad: defend button end", "null");
			// notify to observers

			_defendButton.setOpacity(100);
			RemoveButtonDefend(event);
		}
		if (checkIsTouch(_jumpButton, x, y)) {
			Log.w("GamePad: jump button end", "null");
			// notify to observers
			
			_jumpButton.setOpacity(100);
			RemoveButtonJump(event);
		}
	}

	@Override
	public boolean ccTouchesBegan(MotionEvent event) {
		
		// check which button is touch
		int pointCnt = event.getPointerCount();
		for (int i = 0; i < pointCnt; i++) {
			float x = event.getX(i);
			float y = event.getY(i);
			buttonDown(event, x, y);
		}
		return super.ccTouchesBegan(event);
	}

	@Override
	public boolean ccTouchesEnded(MotionEvent event) {
		// check which button is touch
		int pointCnt = event.getPointerCount();
		for (int i = 0; i < pointCnt; i++) {

			float x = event.getX(i);
			float y = event.getY(i);

			switch (event.getActionMasked()) {
			case MotionEvent.ACTION_POINTER_UP:
				Log.w("ACTION_POINTER_UP", "null");
				buttonUp(event, x, y);
				break;
			case MotionEvent.ACTION_UP:
				Log.w("ACTION_UP", "null");
				buttonUp(event, x, y);
				break;
			default:
				break;
			}

		}
		return super.ccTouchesEnded(event);
	}

	@Override
	public boolean ccTouchesMoved(MotionEvent event) {
		ArrayList<KEY> downButtonsTemp = new ArrayList<GamePad.KEY>();
		for (int i = 0; i < _DownButtons.size(); i++) {
			downButtonsTemp.add(_DownButtons.get(i));
		}
		_DownButtons.clear();
		float x = event.getX();
		float y = event.getY();
		Log.w("GamePad: drag point ", "x=" + x + " y=" + y);
		
		if (_playWithSensor) {
			// move left, right
			if (sensorY > offSet) {
				if (sensorZ > offSet) {
					_DownButtons.add(KEY.RIGHT);
				}
				if (sensorZ < -offSet) {
					_DownButtons.add(KEY.LEFT);
				}
			}
			if (sensorY < -offSet) {
				if (sensorZ > offSet) {
					_DownButtons.add(KEY.LEFT);
				}
				if (sensorZ < offSet) {
					_DownButtons.add(KEY.RIGHT);
				}
			}

			// move up, down
			if (x0 >= 0) {
				if (sensorX > x0 + offSet) {
						_DownButtons.add(KEY.DOWN);
				
				}
				if (sensorX < x0 - offSet) {
						_DownButtons.add(KEY.UP);
				}
			} else {
				if (sensorX > x0 + offSet) {
						_DownButtons.add(KEY.UP);
				}
				if (sensorX < x0 - offSet) {
						_DownButtons.add(KEY.DOWN);
				}
			}
		}
		
		for (int i = 0; i < downButtonsTemp.size(); i++) {
			KEY buttonName = downButtonsTemp.get(i);
			switch (buttonName) {
			case ATTACK:
				if (checkIsTouch(_attackButton, x, y)) {
					_DownButtons.add(KEY.ATTACK);
				}
				break;
			case DEFEND:
				if (checkIsTouch(_defendButton, x, y)) {
					_DownButtons.add(KEY.DEFEND);
				}
				break;
			case JUMP:
				if (checkIsTouch(_jumpButton, x, y)) {
					_DownButtons.add(KEY.JUMP);
				}
				break;
			default:
				break;
			}
		}

		for (int i = 0; i < downButtonsTemp.size(); i++) {
			if (_DownButtons.contains(downButtonsTemp.get(i))) {
				continue;
			} else {
				notifyUpEvent(downButtonsTemp.get(i), event);
			}
		}
		Log.w("GamePadBug: ---begin up----------------", "null");
		for (int i = 0; i < _DownButtons.size(); i++) {
			Log.w("GamePadBug: buttonDown move", _DownButtons.get(i).toString());
		}
		Log.w("GamePadBug: ---end up------------------", "null");
		return super.ccTouchesMoved(event);
	}

	// /////////////////////////////////////////////////////////////////////////
	private void notifyUpEvent(KEY key, MotionEvent event) {
		switch (key) {
		case UP:
			for (GamePadListener element : _observerGamePads) {
				element.upButtonUp(event);
			}
			break;
		case DOWN:
			for (GamePadListener element : _observerGamePads) {
				element.downButtonUp(event);
			}
			break;
		case LEFT:
			for (GamePadListener element : _observerGamePads) {
				element.leftButtonUp(event);
			}
			break;
		case RIGHT:
			// notify to observers
			for (GamePadListener element : _observerGamePads) {
				element.rightButtonUp(event);
			}

			break;
		case ATTACK:
			// notify to observers
			for (GamePadListener element : _observerGamePads) {
				element.attackButtonUp(event);
			}

			break;
		case DEFEND:
			// notify to observers
			for (GamePadListener element : _observerGamePads) {
				element.defendButtonUp(event);
			}

			break;
		case JUMP:
			// notify to observers
			for (GamePadListener element : _observerGamePads) {
				element.jumpButtonUp(event);
			}

			break;
		default:
			break;
		}
	}

	// ///////////////KEYBOARD//////////////////////////////////////////////////
	@Override
	public boolean ccKeyDown(int keyCode, KeyEvent event) {
		Log.w("GamePad key down", Integer.toString(keyCode));
		boolean alreadyKeyDown = false;
		switch (keyCode) {
		case 21:// left\
			alreadyKeyDown = checkIsKeyDowned(KEY.LEFT);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.leftButtonDown(null);
				}
				_DownButtons.add(KEY.LEFT);
			}
			break;
		case 22:// right
			alreadyKeyDown = checkIsKeyDowned(KEY.RIGHT);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.rightButtonDown(null);
				}
				_DownButtons.add(KEY.RIGHT);
			}
			break;
		case 19:// up
			alreadyKeyDown = checkIsKeyDowned(KEY.UP);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.upButtonDown(null);
				}
				_DownButtons.add(KEY.UP);
			}
			break;
		case 20:// down
			alreadyKeyDown = checkIsKeyDowned(KEY.DOWN);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.downButtonDown(null);
				}
				_DownButtons.add(KEY.DOWN);
			}
			break;
		case 29:// a
			alreadyKeyDown = checkIsKeyDowned(KEY.ATTACK);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.attackButtonDown(null);
				}
				_DownButtons.add(KEY.ATTACK);
			}
			break;
		case 47:// s
			alreadyKeyDown = checkIsKeyDowned(KEY.JUMP);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.jumpButtonDown(null);
				}
				_DownButtons.add(KEY.JUMP);
			}
			break;
		case 32:// d
			alreadyKeyDown = checkIsKeyDowned(KEY.DEFEND);
			if (!alreadyKeyDown) {
				for (GamePadListener element : _observerGamePads) {
					element.defendButtonDown(null);
				}
				_DownButtons.add(KEY.DEFEND);
			}
			break;
		}
		return super.ccKeyDown(keyCode, event);
	}

	private boolean checkIsKeyDowned(KEY key) {
		boolean alreadyKeyDown = false;
		for (int i = 0; i < _DownButtons.size(); i++) {
			if (_DownButtons.contains(key))
				alreadyKeyDown = true;
		}
		return alreadyKeyDown;
	}

	@Override
	public boolean ccKeyUp(int keyCode, KeyEvent event) {
		Log.w("GamePad key up", Integer.toString(keyCode));
		switch (keyCode) {
		case 21:// left\
			for (GamePadListener element : _observerGamePads) {
				element.leftButtonUp(null);
			}
			_DownButtons.remove(KEY.LEFT);
			break;
		case 22:// right
			for (GamePadListener element : _observerGamePads) {
				element.rightButtonUp(null);
			}
			_DownButtons.remove(KEY.RIGHT);
			break;
		case 19:// up
			for (GamePadListener element : _observerGamePads) {
				element.upButtonUp(null);
			}
			_DownButtons.remove(KEY.UP);
			break;
		case 20:// down
			for (GamePadListener element : _observerGamePads) {
				element.downButtonUp(null);
			}
			_DownButtons.remove(KEY.DOWN);
			break;
		case 29:// a
			for (GamePadListener element : _observerGamePads) {
				element.attackButtonUp(null);
			}
			_DownButtons.remove(KEY.ATTACK);
			break;
		case 47:// s
			for (GamePadListener element : _observerGamePads) {
				element.jumpButtonUp(null);
			}
			_DownButtons.remove(KEY.JUMP);
			break;
		case 32:// d
			for (GamePadListener element : _observerGamePads) {
				element.defendButtonUp(null);
			}
			_DownButtons.remove(KEY.DEFEND);
			break;
		}
		return super.ccKeyUp(keyCode, event);
	}

	// /////////////////////////////////////////////////////////////////////////

	// ///////////////SENSOR////////////////////////////////////////////////////
	public static void HandleSensor(SensorEvent event) {
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			if (x0 == 100)
				x0 = event.values[0];
			sensorX = event.values[0];
			sensorY = event.values[1];
			sensorZ = event.values[2];
			MoveWithSensor(sensorX, sensorY, sensorZ);
			ActionAccelerometer(sensorX, sensorY, sensorZ);
		}
	}

	private static void MoveWithSensor(float x, float y, float z) {
		

		if (_playWithSensor) {
			// move left, right
			if (y >= -offSet && y <= offSet) {
				RemoveButtonLeft(null);
				RemoveButtonRight(null);
			}

			if (y > offSet) {
				if (z > offSet) {
					AddButtonRight(null);
				}
				if (z < -offSet) {
					AddButtonLeft(null);
				}
			}
			if (y < -offSet) {
				if (z > offSet) {
					AddButtonLeft(null);
				}
				if (z < offSet) {
					AddButtonRight(null);

				}
			}

			// move up, down
			if (x >= x0 - offSet && x <= x0 + offSet) {
				RemoveButtonUp(null);
				RemoveButtonDown(null);
			}

			if (x0 >= 0) {
				if (x > x0 + offSet) {
					if (z >= 0) {
						AddButtonDown(null);
					} else {
						AddButtonUp(null);
					}
				}
				if (x < x0 - offSet) {
					if (z >= 0) {
						AddButtonUp(null);
					} else {
						AddButtonDown(null);
					}
				}
			} else {
				if (x > x0 + offSet) {
					if (z >= 0) {
						AddButtonUp(null);
					} else {
						AddButtonDown(null);
					}
				}
				if (x < x0 - offSet) {
					if (z >= 0) {
						AddButtonDown(null);
					} else {
						AddButtonUp(null);
					}
				}
			}
		}
	}

	private static void ActionAccelerometer(float x, float y, float z) {
		float accelationSquareRoot = (x * x + y * y + z * z)
				/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
		long actualTime = System.currentTimeMillis();
		if (accelationSquareRoot >= 2) //
		{
			if (actualTime - lastUpdate < 200) {
				return;
			}
			lastUpdate = actualTime;
			//lap chieu manh nhat vao
			// Toast.makeText(this, "Device was shuffed", Toast.LENGTH_SHORT)
			// .show();
		}
	}
	// /////////////////////////////////////////////////////////////////////////
}
